import HashHistory from './history/hash'
import HTML5History from './history/html5'
import CreateMatchers from './create-matchers'

import { install } from './install'

class VueRouter {
  constructor (options) {
    this.apps = []
    this.app = null
    this.mode = options.mode || 'history' // 路由模式 history｜ hash
    // 路由实例对象。根据路由模式进行选择性实例化
    this.history = options.mode === 'history' ? new HTML5History(this, options) : new HashHistory(this, options)
    this.options = options // 路由初始化选项
    this.beforeHooks = [] // 钩子：beforeEach 的集合数组
    this.afterHooks = [] // 钩子：afterEach 的集合数组
    this.matchers = new CreateMatchers(options.routes || [], this)
  }

  init (app) {
    this.apps.push(app)
    app.$once('hook:destroyed', () => {
      this.apps = this.apps.filter(ins => app !== ins)
      if (this.app === app) {
        this.app = this.apps[0] || null
      }
    })

    if (this.app) return
    const history = this.history

    if (history instanceof HTML5History) {
      history.transitionTo(history.getCurrentLocation())
    }

    history.listen((route) => {
      app._route = route
    })
  }

  push (raw) {
    // 路由push方法
    this.history.push(raw)
  }

  match (location) {
    return this.matchers.match(location)
  }

  beforeEach (callback) {
    // 将注册的钩子，放进 beforeHooks 里面，并返回可以删除刚注册的钩子的函数。
    return registerHook(this.beforeHooks, callback)
  }

  afterEach (callback) {
    // 将注册的钩子，放进 afterHooks 里面，并返回可以删除刚注册的钩子的函数。
    return registerHook(this.afterHooks, callback)
  }
}

function registerHook (list, fn) {
  list.push(fn)

  // 返回可以删除刚注册的钩子的函数。
  // 在 https://router.vuejs.org/zh/api/#router-beforeresolve 中：
  // 2.5.0+ 这三个方法都返回一个移除已注册的守卫/钩子的函数。
  return () => {
    const i = list.indexOf(fn)
    if (i > -1) list.splice(i, 1)
  }
}

VueRouter.install = install

export default VueRouter
